<template>
  <div class="container">
    <div class="left-board">
      <el-scrollbar class="left-scrollbar">
        <div class="components-list">
          <div v-for="(item, listIndex) in state.leftComponents" :key="listIndex" class="components-part">
            <div class="components-title">{{ item.title }}</div>
            <draggable
              class="components-draggable"
              :list="item.list"
              item-key="id"
              :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
              :clone="cloneComponent"
              draggable=".components-item"
              filter=".disabled"
              :sort="false"
              @end="onEnd"
            >
              <template #item="{ element, index }">
                <div
                  :key="index"
                  class="components-item"
                  :class="{ disabled: element._config_.dragDisabled }"
                  @click="addComponent(element)"
                >
                  <div class="components-body">
                    <i :class="element._config_.tagIcon" />
                    {{ element._config_.label }}
                  </div>
                </div>
              </template>
            </draggable>
          </div>
        </div>
      </el-scrollbar>
    </div>
    <div class="center-board">
      <div class="action-bar">
        <div class="action-bar-right">
          <el-button
            :icon="Cellphone"
            :class="{ 'unActive-btn': state.showType != 'pc' }"
            size="small"
            text
            @click="state.showType = 'pc'"
          >
            桌面端
          </el-button>
          <el-button
            :icon="Monitor"
            :class="{ 'unActive-btn': state.showType != 'app' }"
            size="small"
            text
            @click="state.showType = 'app'"
          >
            移动端
          </el-button>
          <el-button class="unActive-btn" :icon="VideoPlay" size="small" text @click="preview">预览</el-button>
          <!-- <el-button icon="el-icon-view" size="small" text @click="showJson" >
            查看json</el-button> -->
          <el-button class="delete-btn unActive-btn" :icon="Delete" size="small" text @click="empty">清空</el-button>
        </div>
      </div>
      <el-scrollbar class="center-scrollbar" v-show="state.showType === 'pc'">
        <el-row class="center-board-row">
          <el-form
            :size="state.formConf.size"
            :label-position="state.formConf.labelPosition"
            :disabled="state.formConf.disabled"
            :label-width="state.formConf.labelWidth + 'px'"
            width="100%"
          >
            <DraggablePanel
              :drawing-list="state.drawingList"
              :animation="200"
              group="componentsGroup"
              @end="onCenterEnd"
              tag="el-row"
              :form-conf="state.formConf"
              :style="{ marginLeft: 0, alignContent: 'start', height: '100%' }"
              :gutter="state.formConf.gutter"
              :active-id="state.activeId"
            >
            </DraggablePanel>
            <!-- <draggable class="drawing-board" 
              :list="state.drawingList"                            
              group="componentsGroup" 
              :animation="300"
              @end='onCenterEnd' 
              tag="el-row"
              itemKey="id" 
              >
              <template #item="{element, index}">
                <DraggableDemo 
                  :key="element._config_.renderKey" 
                  :drawingList="state.drawingList"  
                  :index="index" :activeId="state.activeId"
                  :formConf="state.formConf" 
                  :activeData="element"
                  />               
              </template>              
            </draggable> -->
            <div v-show="!state.drawingList.length" class="empty-info">
              <img :src="emptyElementPng" alt="" class="empty-img" />
            </div>
          </el-form>
        </el-row>
      </el-scrollbar>
      <!-- <div id="ipad" v-show="state.showType==='app'">
        <div class="outeripad">
          <div class="ipadbody">
            <el-scrollbar class="center-scrollbar">
              <el-row class="center-board-row" :gutter="state.formConf.gutter">
                <el-form :size="state.formConf.size" :label-position="state.formConf.labelPosition"
                  :disabled="state.formConf.disabled" :label-width="state.formConf.labelWidth + 'px'">
                  <draggable class="drawing-board" :list="state.drawingList" :animation="340"
                    group="componentsGroup" @end='onCenterEnd'>
                    <draggable-item-app v-for="(element, index) in state.drawingList"
                      :key="element.renderKey" :drawing-list="state.drawingList" :element="element"
                      :index="index" :active-id="state.activeId" :form-conf="state.formConf"
                      @activeItem="activeFormItem" @copyItem="drawingItemCopy"
                      @deleteItem="drawingItemDelete" :put="shouldClone" :end='onTableEnd' />
                  </draggable>
                  <div v-show="!state.drawingList.length" class="empty-info app-empty-info">
                    <img src="/@/assets/images/emptyElement.png" alt="" class="empty-img">
                  </div>
                </el-form>
              </el-row>
            </el-scrollbar>
          </div>
        </div>
      </div> -->
    </div>
    <RightPanel
      v-model:active-data="state.activeData"
      v-model:form-conf="state.formConf"
      :show-field="!!state.drawingList.length"
      :model-type="modelType"
      :web-type="webType"
      v-model:drawingList="state.drawingList"
    />
  </div>
</template>

<script lang="ts" setup name="FormGenerator">
import { reactive, watch, nextTick, defineAsyncComponent, ref, provide } from "vue";
import draggable from "vuedraggable";
import { debounce } from "throttle-debounce";
import { ElMessageBox } from "element-plus";
//import JsonDrawer from './JsonDrawer'
import RightPanel from "./RightPanel.vue";
//import Preview from '../preview'
import { deepClone } from "../utils";
//import DraggableItemApp from './DraggableItemApp'
//import { noVModelList,noTableAllowList } from '../configs/extConfig'
//import { saveDrawingList, getIdGlobal } from "../utils/db";
import configs from "../configs";
import { useFormData } from "../stores/formStore";
import emptyElementPng from "@/assets/images/emptyElement.png";
import { Cellphone, Delete, Monitor, VideoPlay } from "@element-plus/icons-vue";
//const DraggableDemo = defineAsyncComponent(() => import('./DraggableDemo.vue'));
const DraggablePanel = defineAsyncComponent(() => import("./DraggablePanel.vue"));
//const idGlobal = getIdGlobal()

const state = reactive({
  isErrorShow: false,
  validResults: [],
  idGlobal: 100,
  formConf: configs.formConf,
  // extComponents: configs.extComponents,
  // customComponents: configs.customComponents,
  //inputComponents: configs.inputComponents,
  // selectComponents: configs.selectComponents,
  // layoutComponents: configs.layoutComponents,
  // commonComponents:configs.commonComponents,
  //customGroupComponents: configs.customGroupComponents,
  drawingList: [] as any,
  activeId: 0,
  //renderKey:0,
  drawerVisible: false,
  generateConf: null,
  activeData: {} as any, //当前组件
  activeTableItem: {} as any,
  activeTabName: "custom",
  drawerSize: "490px",
  flowConditions: [],
  tempActiveData: {} as any,
  formData: {} as any,
  showType: "pc",
  leftComponents: [
    {
      title: "基础控件",
      list: configs.inputComponents
    }
  ]
});

const props = defineProps({ conf: Object, dbType: String, webType: String, modelType: String });

const stores = useFormData();
const storeData = reactive({
  allTable: stores.allTable,
  hasTable: stores.allTable.length > 0
});

const created = () => {
  if (typeof props.conf === "object" && props.conf !== null) {
    state.drawingList = deepClone(props.conf.fields);
    Object.assign(state.formConf, props.conf);
    state.idGlobal = state.formConf.idGlobal;
    //if (this.drawingList.length) this.activeFormItem(this.drawingList[0])
  } else {
    state.drawingList = [];
    state.idGlobal = 100;
  }
};

// 供父组件使用 获取表单JSON
const getData = () => {
  return new Promise((resolve, reject) => {
    if (!state.drawingList.length) {
      reject({ msg: "表单不允许为空", target: 1 });
      return;
    }
    const loop = (list: any) => {
      for (let i = 0; i < list.length; i++) {
        const e = list[i];
        const config = e._config_;
        if (
          storeData.hasTable &&
          config.layout === "StandaloneItem" &&
          !configs.noVModelList.includes(config.goodKey) &&
          !e.vModel
        ) {
          reject({ msg: `请选择${config.label}的控件字段`, target: 1 });
          break;
        }
        if (config.goodKey === "billRule") {
          if (!config.rule) {
            reject({ msg: "单据组件“选择模板”属性为必填项", target: 1 });
            break;
          }
        }
        if (config.goodKey === "relationForm") {
          if (!e.modelId) {
            reject({ msg: "关联表单控件“关联功能”属性为必填项", target: 1 });
            break;
          }
          if (!e.relationField) {
            reject({ msg: "关联表单控件“显示字段”属性为必填项", target: 1 });
            break;
          }
        }
        if (config.goodKey === "popupSelect") {
          if (!e.interfaceId) {
            reject({ msg: "弹窗选择控件“远端数据”属性为必填项", target: 1 });
            break;
          }
          if (!e.propsValue) {
            reject({ msg: "弹窗选择控件“储存字段”属性为必填项", target: 1 });
            break;
          }
          if (!e.relationField) {
            reject({ msg: "弹窗选择控件“显示字段”属性为必填项", target: 1 });
            break;
          }
        }
        if (config.layout === "ContainerItem" && !config.children.length) {
          reject({ msg: `您的${config.label}控件中没有组件`, target: 1 });
          break;
        }
        if (config && config.children && Array.isArray(config.children)) {
          loop(config.children);
        }
      }
    };
    loop(state.drawingList);
    AssembleFormData();
    if (state.formData.hasPrintBtn && !state.formData.printId) {
      reject({ msg: `请选择打印模板`, target: 1 });
    }
    resolve({ formData: state.formData, target: 1 });
  });
};
//  阻止表格中嵌套行容器
// const shouldClone = (to: any, from: any, target: any, event: any, conf: any) => {
//   const targetConf = target._underlying_vm_;
//   const isRowContainer = conf._config_.cmpType === "common" && conf._config_.rowType === "layout";
//   if (isRowContainer) return true;
//   if (conf.cmpType === "custom") return false;
//   if (conf._config_.rowType === "table") {
//     if (configs.noTableAllowList.includes(targetConf._config_.goodKey)) {
//       ElMessage.warning(`子表内暂不支持使用该组件`);
//       return false;
//     }
//     if (targetConf._config_.layout === "ContainerItem") return false;
//     if (storeData.hasTable) {
//       if (!conf._config_.tableName) {
//         ElMessage.warning(`子表请先关联数据表`);
//         return false;
//       }
//     }
//     state.activeData = targetConf;
//     state.activeTableItem = conf;
//   }
//   return true;
// };
const activeFormItem = (element: any) => {
  if (state.activeId === element._config_.renderKey) return;
  state.activeData = element;
  state.activeId = element._config_.renderKey;
};
//组件拖放结束，激活新元素为当前元素
const onEnd = (obj: any) => {
  if (obj.from !== obj.to) {
    state.activeData = state.tempActiveData;
    state.activeId = state.tempActiveData._config_.renderKey;
  }
  if (obj.to.className.indexOf("table") > -1) {
    state.activeData._config_.isSubTable = true;
    if (storeData.hasTable) {
      state.activeData._config_.relationTable = state.activeTableItem._config_.tableName;
      state.activeData.vModel = "";
    }
  }
};
//画布拖放结束
const onCenterEnd = (obj: any) => {
  if (obj.from == obj.to) return;
  if (obj.to.className.indexOf("table") > -1) {
    state.activeData._config_.isSubTable = true;
    if (storeData.hasTable) {
      state.activeData._config_.relationTable = state.activeTableItem._config_.tableName;
      state.activeData.vModel = "";
    }
  }
};
//组件拖放到table中
// const onTableEnd = (obj: any, target: any, conf: any) => {
//   if (obj.from == obj.to) return;
//   if (obj.to.className.indexOf("table") < 0) {
//     state.activeData._config_.isSubTable = false;
//     if (storeData.hasTable) state.activeData.vModel = "";
//   } else {
//     //该组件是否属于子表
//     state.activeData._config_.isSubTable = true;
//     if (storeData.hasTable) {
//       state.activeData._config_.relationTable = state.activeTableItem._config_.tableName;
//       state.activeData.vModel = "";
//     }
//   }
// };
const addComponent = (item: any) => {
  if (item._config_.dragDisabled) return;
  const clone = cloneComponent(item);
  state.drawingList.push(clone);
  activeFormItem(clone);
};
const cloneComponent = (origin: any) => {
  const clone = deepClone(origin);
  let item = ref(clone);
  const config = item.value._config_;
  config.span = state.formConf.span; // 生成代码时，会根据span做精简判断
  createIdAndKey(item.value);
  // clone.placeholder !== undefined && (clone.placeholder += config.label)
  state.tempActiveData = item;
  return state.tempActiveData;
};
const createIdAndKey = (item: any) => {
  const config = item._config_;
  config.formId = ++state.idGlobal;
  config.renderKey = +new Date(); // 改变renderKey后可以实现强制更新组件
  if (config.layout === "StandaloneItem") {
    if (!storeData.hasTable) {
      // 分割线和按钮不加vModel
      if (configs.noVModelList.indexOf(config.goodKey) < 0) {
        item.vModel = toggleVmodelCase(`${config.goodKey}Field${state.idGlobal}`);
      }
    } else {
      if (configs.noVModelList.indexOf(config.goodKey) < 0) {
        item.vModel = "";
      }
    }
  } else if (config.layout === "ContainerItem") {
    if (config.goodKey === "table") {
      item.vModel = toggleVmodelCase(`${config.goodKey}Field${state.idGlobal}`);
    }
    config.componentName = `row${state.idGlobal}`;
    !Array.isArray(config.children) && (config.children = []);
  }
  if (Array.isArray(config.children)) {
    config.children = config.children.map((childItem: any) => createIdAndKey(childItem));
  }
  return item;
};
const toggleVmodelCase = (str: string) => {
  const dbType = props.dbType || "";
  if (dbType.toLowerCase() === "Oracle".toLowerCase() || dbType.toLowerCase() === "DM8".toLowerCase()) {
    return str.toUpperCase();
  }
  if (dbType.toLowerCase() === "PostgreSQL".toLowerCase() || dbType.toLowerCase() === "KingBaseES".toLowerCase()) {
    return str.toLowerCase();
  }
  return str;
};
const AssembleFormData = () => {
  state.formData = {
    ...state.formConf,
    fields: deepClone(state.drawingList)
  };
};
const empty = () => {
  ElMessageBox.confirm("确定要清空所有组件吗？", "提示", { type: "warning" })
    .then(() => {
      state.drawingList = [];
      state.idGlobal = 100;
    })
    .catch();
};
const drawingItemCopy = (item: any, parent: any) => {
  let clone = deepClone(item);
  clone = createIdAndKey(clone);
  parent.push(clone);
  activeFormItem(clone);
};
const drawingItemDelete = (data: any) => {
  const index = state.drawingList.findIndex(item => item._config_.renderKey == data._config_.renderKey);
  state.drawingList.splice(index, 1);
  nextTick(() => {
    const len = state.drawingList.length;
    if (len) {
      activeFormItem(state.drawingList[len - 1]);
    } else {
      state.drawingList = [];
    }
  });
};
const preview = () => {
  AssembleFormData();
  //previewVisible = true
};
// const showJson = () => {
//   AssembleFormData();
//   //jsonDrawerVisible = true
// };
// const refreshJson = (data: any) => {
//   state.drawingList = deepClone(data.fields);
//   delete data.fields;
//   state.formConf = data;
// };

//传递方法
provide("activeFormItem", activeFormItem);
provide("deleteItem", drawingItemDelete);
provide("copyItem", drawingItemCopy);
watch(
  () => state.drawingList,
  val => {
    if (val.length === 0) {
      state.idGlobal = 100;
      state.activeId = 0;
    }
    //debounce(400,saveDrawingList(state.drawingList)) // 使用了deep 所以刷新会比较频繁
    debounce(400, stores.setDrawingList(state.drawingList));
  },
  {
    deep: true,
    immediate: true
  }
);

created();
// 将这个方法暴露出去,这样父组件就可以使用了哈
defineExpose({
  getData
});
</script>
<style lang="scss">
@import "../styles/index";
@import "../styles/home";
</style>
